/**
 *
 * 2007-11-2 上午11:09:49
 * @author xuhuan
 */

package edu.ccut.saturn.studio.logic.model.xml.loader;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.geometry.Point;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import edu.ccut.saturn.studio.logic.model.Shape;
import edu.ccut.saturn.studio.logic.model.saturn.ErrorInfo;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnArg;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnContent;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnParameter;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnValidate;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnWebContextNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnWebContextParameter;
import edu.ccut.saturn.studio.util.ConversionUtil;

public abstract class NodeLoader {

	protected String getNodeAttributeValue(Node node, String key) {
		Node attribute = node.getAttributes().getNamedItem(key);

		if (attribute != null) {
			return attribute.getNodeValue();
		}

		return "";
	}

	protected String getNodeElementValue(Node node, String key) {
		NodeList childNodes = node.getChildNodes();

		for (int i = 0; i < childNodes.getLength(); ++i) {
			Node child = childNodes.item(i);
			if (child.getNodeName().equals(key)) {
				if (child.getFirstChild() != null) {
					return child.getFirstChild().getNodeValue();
				}

				return "";
			}
		}

		return "";
	}
	
	protected String getConifgAttributeValue(Node node, String key) {
		if(node != null){
			Node attribute = node.getAttributes().getNamedItem(key);
			return attribute.getNodeValue();
		}
		return "SaturnComponentNode";
	}

	protected Node getChildNode(Node parentNode, String nodeKey) {
		NodeList children = parentNode.getChildNodes();

		for (int i = 0; i < children.getLength(); ++i) {
			Node child = children.item(i);

			if (child.getNodeName().equals(nodeKey)) {
				return child;
			}
		}

		return null;
	}

	protected List<Node> getChildNodes(Node parentNode, String nodeKey) {
		NodeList children = parentNode.getChildNodes();

		List<Node> childNodes = new ArrayList<Node>();

		for (int i = 0; i < children.getLength(); ++i) {
			Node child = children.item(i);

			if (child.getNodeName().equals(nodeKey)) {
				childNodes.add(child);
			}
		}

		return childNodes;
	}

	protected Point getLocation(Node node) {
		String x = this.getNodeAttributeValue(node, Shape.KEY_ATTRIBUTE_X);
		String y = this.getNodeAttributeValue(node, Shape.KEY_ATTRIBUTE_Y);

		int xInt = 0;
		int yInt = 0;
		try {
			xInt = Integer.parseInt(x);
			yInt = Integer.parseInt(y);
		} catch (NumberFormatException e) {
			// e.printStackTrace();
		}

		return new Point(xInt, yInt);
	}

	protected List<SaturnParameter> getParameters(Node node) {
		Node parametersNode = this
				.getChildNode(node, Shape.KEY_NODE_PARAMETERS);

		List<SaturnParameter> parameters = new ArrayList<SaturnParameter>();

		if (parametersNode != null) {
			List<Node> parameterNodes = this.getChildNodes(parametersNode,
					Shape.KEY_NODE_PARAMETER);

			for (Node parameterNode : parameterNodes) {
				parameters.add(this.getParameter(parameterNode));
			}
		}
		ConversionUtil.scopeMapFromXmlToSurface(parameters);
		return parameters;
	}

	protected List<SaturnContent> getContents(Node node) {
		Node contentsNode = this.getChildNode(node,
				Shape.KEY_NODE_TANSFORM_CONTENTS);
		List<SaturnContent> contents = new ArrayList<SaturnContent>();
		if (contentsNode != null) {
			List<Node> contentNodes = this.getChildNodes(contentsNode,
					Shape.KEY_NODE_TANSFORM_CONTENT);
			for (Node contentNode : contentNodes) {
				contents.add(this.getContent(contentNode));

			}
		}
		return contents;
	}

	private SaturnContent getContent(Node contentNode) {
		String id = this.getNodeAttributeValue(contentNode,
				Shape.KEY_NODE_TRANSFORM_ID);
		String type = this.getNodeAttributeValue(contentNode,
				Shape.KEY_NODE_TRANSFORM_TYPE);
		String contentValueKey = this.getNodeElementValue(contentNode,
				Shape.KEY_NODE_TRANSFORM_CONTENT_VALUE_KEY);
		SaturnContent saturnContent = new SaturnContent();
		saturnContent.setId(id);
		saturnContent.setType(type);
		saturnContent.setContentValueKey(contentValueKey);
		return saturnContent;
	}
	
	protected List<SaturnWebContextParameter> getWebParameters(Node node){
		Node webParametersNode = this.getChildNode(node, SaturnWebContextNode.WEB_CONTEXT_VALUE_MOVES);
		List<SaturnWebContextParameter> webParameters = new ArrayList<SaturnWebContextParameter>();
		if(webParametersNode != null){
			List<Node> webParameterNodes = this.getChildNodes(webParametersNode, SaturnWebContextNode.WEB_CONTEXT_VALUE_MOVE);
			for(Node webParameterNode: webParameterNodes){
				webParameters.add(this.getWebParameter(webParameterNode));
			}
		}
		
		return webParameters;
	}
	
	private SaturnWebContextParameter getWebParameter(Node webParameterNode){
		String id = this.getNodeAttributeValue(webParameterNode, SaturnWebContextNode.WEB_CONTEXT_ID);
		String key = this.getNodeAttributeValue(webParameterNode, SaturnWebContextNode.WEB_CONTEXT_KEY);
		String scope = this.getNodeAttributeValue(webParameterNode, SaturnWebContextNode.WEB_CONTEXT_SCOPE);
		String newKey = this.getNodeAttributeValue(webParameterNode, SaturnWebContextNode.WEB_CONTEXT_NEW_KEY);
		String newScope = this.getNodeAttributeValue(webParameterNode, SaturnWebContextNode.WEB_CONTEXT_NEW_SCOPE);
		String isDelete = this.getNodeAttributeValue(webParameterNode, SaturnWebContextNode.WEB_CONTEXT_ISDELETE);
		
		SaturnWebContextParameter saturnWebContextParameter = new SaturnWebContextParameter();
		saturnWebContextParameter.setId(id);
		saturnWebContextParameter.setKey(key);
		saturnWebContextParameter.setScope(scope);
		saturnWebContextParameter.setNewKey(newKey);
		saturnWebContextParameter.setNewScope(newScope);
		saturnWebContextParameter.setIsDelete(isDelete);
		
		return saturnWebContextParameter;
	}

	private SaturnParameter getParameter(Node parameterNode) {
		String id = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_ID);
		String name = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_NAME);
		String classType = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_CLASS_TYPE);
		String passingType = this.getNodeAttributeValue(parameterNode,
				Shape.KEY_PARAMETER_ATTRIBUTE_PASSING_TYPE);

		String valueKey = this.getNodeElementValue(parameterNode,
				Shape.KEY_PARAMETER_NODE_VALUE_KEY);
		String scope = this.getNodeElementValue(parameterNode,
				Shape.KEY_PARAMETER_NODE_SCOPE);
		String description = this.getNodeElementValue(parameterNode,
				Shape.KEY_PARAMETER_NODE_DESCRIPTION);

		SaturnParameter saturnParameter = new SaturnParameter();
		saturnParameter.setId(id);
		saturnParameter.setName(name);
		saturnParameter.setClassType(classType);
		saturnParameter.setPassingType(passingType);
		saturnParameter.setValueKey(valueKey);
		saturnParameter.setScope(scope);
		saturnParameter.setDescription(description);
		// TODO:做判断
		if (isChildNoded(parameterNode, Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATES)) {
			this.getValidates(isChildNode(parameterNode,
					Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATES), saturnParameter);
		}
		
		return saturnParameter;
	}

	private boolean isChildNoded(Node node, String tagname) {
		if (node != null) {
			NodeList validates = node.getChildNodes();
			for (int i = 0; i < validates.getLength(); i++) {
				if (validates.item(i).getNodeName().equals(tagname)) {
					return true;
				}
			}
		}
		return false;
	}
	
	public String getConfigInfo(Node node,String key){
		Node config = isChildNode(node, "configuration");
		if(config == null){
			return "SaturnComponentNode";
		}
		return getNodeAttributeValue(config, key);
	}

	private Node isChildNode(Node node, String tagname) {
		if (node != null) {
			NodeList validates = node.getChildNodes();
			for (int i = 0; i < validates.getLength(); i++) {
				if (validates.item(i).getNodeName().equals(tagname)) {
					return validates.item(i);
				}
			}
		}
		return null;
	}

	/**
	 * 
	 * @param node
	 *            is already validates
	 * @param saturnParameter
	 */
	private void getValidates(Node node, SaturnParameter saturnParameter) {

		String isValidate = this.getNodeAttributeValue(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_CLASS_IS_VALIDATE);

		List<SaturnValidate> validates = new ArrayList<SaturnValidate>();

		List<Node> validateNodes = this.getChildNodes(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATE);

		if (validateNodes != null) {
			int i = 1;
			for (Node saturnValidateNode : validateNodes) {

				validates.add(this.getValidate(saturnValidateNode, i));
				i++;

			}
		}
		saturnParameter.setIsValidate(isValidate);
		saturnParameter.setValidates(validates);

	}

	private SaturnValidate getValidate(Node node, int i) {
		String key = this.getNodeElementValue(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATE_KEY);
		String name = this.getNodeElementValue(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_NAME);
		String vslidateClass = this.getNodeElementValue(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATE_CLASS);
		String description = this.getNodeElementValue(node,
				Shape.KEY_PARAMETER_NODE_DESCRIPTION);
		String jsMethodName = this.getNodeElementValue(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATE_JS_METHOD_NAME);
		String customJsMethod = this.getNodeElementValue(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATE_CUSTOM_JS_METHOD);
		List<SaturnArg> args = new ArrayList<SaturnArg>();
		args = this.getArgs(node);
		
		List<ErrorInfo> errorInfos = new ArrayList<ErrorInfo>();
		errorInfos = this.getErrorInfoList(node);
		
		List<String> eventInfos = new ArrayList<String>();
		eventInfos = this.getEventInfoList(node);

		SaturnValidate saturnValidate = new SaturnValidate();
		saturnValidate.setKey(key);
		saturnValidate.setName(name);
		saturnValidate.setValidateClass(vslidateClass);
		saturnValidate.setDescription(description);
		saturnValidate.setArgs(args);
		
		saturnValidate.setJsMethodName(jsMethodName);
		saturnValidate.setCustomJsMethod(customJsMethod);
		saturnValidate.setId("" + i);
		saturnValidate.setErrorInfos(errorInfos);
		saturnValidate.setEventInfos(eventInfos);
		saturnValidate.setValidateType(getValidateType(node));
		return saturnValidate;
	}

	protected List<SaturnArg> getArgs(Node node) {
		Node argsNode = this.getChildNode(node,
				Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATE_ARGS);
		List<SaturnArg> args = new ArrayList<SaturnArg>();
		if (args != null) {
			int i = 1;
			List<Node> argNodes = this.getChildNodes(argsNode,
					Shape.KEY_PARAMETER_ATTRIBUTE_VALIDATE_ARG);

			for (Node argNode : argNodes) {
				args.add(this.geSaturnArg(argNode, i));
				i++;
			}

		}
		return args;
	}
	protected List<ErrorInfo> getErrorInfoList(Node node) {
		Node errorInfosN = this.getChildNode(node,
				"errorInfos");
		List<ErrorInfo> errorInfos = new ArrayList<ErrorInfo>();
		if (errorInfosN != null) {
			List<Node> argNodes = this.getChildNodes(errorInfosN,
					"errorInfo");
			
			for (Node errorInfo : argNodes) {
				errorInfos.add(this.getErrorInfo(errorInfo));
			}
			
		}
		return errorInfos;
	}
	protected List<String> getEventInfoList(Node node) {
		Node eventInfosN = this.getChildNode(node,
		"eventInfos");
		List<String> eventInfos = new ArrayList<String>();
		if (eventInfosN != null) {
			List<Node> eventInfoNs = this.getChildNodes(eventInfosN,
			"eventInfo");
			
			for (Node errorInfoN : eventInfoNs) {
				eventInfos.add(errorInfoN.getFirstChild().getNodeValue());
			}
			
		}
		return eventInfos;
	}
	protected String getValidateType(Node node) {
		return this.getNodeElementValue(node, "validateType").trim();
	
	}

	private SaturnArg geSaturnArg(Node argNode, int id) {

		String arg = "";
		NodeList child = argNode.getChildNodes();
		for (int i = 0; i < child.getLength(); i++) {
			if (child.item(i).getNodeType() == Node.TEXT_NODE) {
				arg = child.item(i).getNodeValue();
			}
		}
		SaturnArg saturnArg = new SaturnArg();
		saturnArg.setArg(arg);
		saturnArg.setId("" + id);
		return saturnArg;
	}
	private ErrorInfo getErrorInfo(Node errorInfoN) {
		
//		String arg = "";
//		NodeList child = errorInfoN.getChildNodes();
//		for (int i = 0; i < child.getLength(); i++) {
//			if (child.item(i).getNodeType() == Node.TEXT_NODE) {
//				arg = child.item(i).getNodeValue();
//			}
//		}
		if(errorInfoN instanceof Element){
			ErrorInfo errorInfo = new ErrorInfo();
			errorInfo.setKey(((Element)errorInfoN).getAttribute("key"));
			errorInfo.setValue(errorInfoN.getFirstChild().getNodeValue().trim());
			return errorInfo;
		}
		return null;
	}

	public abstract List<Shape> loadNodes(Element root);
}
